#! /usr/bin/env node

const commander = require('commander')
const shell = require('shelljs')
const chalk = require('chalk')
const fs = require('fs')
const path = require('path')
const executeDir = process.cwd()
const resolve = (p) => (path.resolve(__dirname, p))
const executeResolve = (p) => (path.resolve(executeDir, p))
const packageConfig = JSON.parse(fs.readFileSync(resolve('../package.json'), {
  encoding: 'utf-8'
}));
const {
  selectPkgManagement,
  inputBranch,
  autoPush,
} = require('./tools')
const log = console.log
const errorDetail = (title, detail) => log(chalk`{bgRed =====> {bold ${title}}}${detail?`\n{red ${detail}}` : ''}`)

commander
  .version(packageConfig.version, '-v, --version')
  .description(packageConfig.description)

commander
  .command('update <packageName> <version> [dirs...]')
  .option('-a, --all', '升级当前目录下所有仓库')
  .option('-s, --some', '升级指定仓库<默认>')
  .action(async (packageName, version, dirs, options) => {
    const dir = executeResolve('./')
    const pkgMgmt = await selectPkgManagement()
    const branch = await inputBranch()
    const isAutoPush = await autoPush()
    let currentDirs = []
    // 如果使用 -a 选项，则遍历命令运行目录下所有的目录
    if (options.all) {
      currentDirs = fs.readdirSync(dir)
    // 否则使用用户输入的目录
    } else {
      currentDirs = dirs
    }
    log(chalk.yellow(`你选择以下目录：\n${currentDirs.join('\n')}`))
    // 遍历选择的目录
    for (const filename of currentDirs) {
      const fullname = path.join(dir, filename)
      const stats = fs.statSync(fullname)
      let pkgJSON
      let installResult
      let inDev = false
      if (!stats.isDirectory()) continue
      try {
        pkgJSON = require(path.join(fullname, 'package.json'))
      } catch (e) {
        pkgJSON = {}
      }
      if (pkgJSON?.dependencies?.[packageName]) {
        inDev = false
      } else if (pkgJSON?.devDependencies?.[packageName]) {
        inDev = true
      } else {
        log(chalk.yellow(`\n${filename} 目录不存在 ${packageName} 包\n`))
        continue
      }

      shell.cd(fullname)

      log(`\n正在升级${chalk.yellow(filename)}仓库...\n`)

      // 暂存当前修改
      const res = shell.exec('git stash --include-untracked', { silent: true })
      const hasStash = res.code === 0 && !res.stdout.includes('No local changes to save')

      const currentBranch = shell.exec('git symbolic-ref --short -q HEAD', { silent: true }).stdout

      if (branch) {
        shell.exec(`git checkout ${branch}`, { silent: true })
        shell.exec(`git pull origin ${branch}`, { silent: true })
      }

      if (pkgMgmt === 'yarn') {
        installResult = shell.exec(`yarn add ${packageName}@${version} ${inDev ? '-D' : ''}`, {
          silent: true
        })
      } else {
        installResult = shell.exec(`npm install ${packageName}@${version} ${inDev ? '-D' : ''}`, {
          silent: true
        })
      }

      let gitResult

      // commit 到仓库
      if (installResult.code === 0) {
        const changedFiles = shell.exec('git diff --name-only', { silent: true }).stdout?.split('\n').filter(f => f !== '')
        if (!changedFiles.length) {
          errorDetail(`升级 ${filename} 仓库失败(升级版本失败)，错误信息：请检查升级的版本与当前版本是否是同一版本`)
          continue
        }
        if ((gitResult = shell.exec(`git add package.json ${pkgMgmt === 'yarn' ? 'yarn.lock' : 'package-lock.json'}`, {
            silent: true
          })).code === 0 &&
          (gitResult = shell.exec(`git commit -m \"chore: 升级 ${packageName} 版本至 ${version}\"`, { silent: true })).code === 0
        ) {
          log(chalk.green(`=====> 升级 ${filename} 仓库成功`))
          if (isAutoPush) {
            if (shell.exec(`git push origin ${branch}:${branch}`).code === 0) {
              log(chalk.yellow(`\n已推动到分支 ${branch}\n`))
            } else {
              log(chalk.red(`\n推动到分支 ${branch} 失败\n`))
            }
          }
        } else {
          errorDetail(`升级 ${filename} 仓库失败(git add 失败)，错误信息:`, gitResult.stderr || gitResult.stdout)
        }
      } else {
        errorDetail(`升级 ${filename} 仓库失败(升级版本失败)，错误信息：`, installResult.stderr || installResult.stdout)
      }
      shell.exec(`git checkout ${currentBranch}`)
      // 如果暂存了之前修改就恢复
      if (hasStash) {
        shell.exec('git stash pop', { silent: true })
      }
    }
    log(chalk.yellow('\n操作完毕'))
  })

commander.parse(process.argv)
